package star.oath.project.battle.util;

import java.util.*;

public class BattleOrderCalculator {

    private Map<String, Integer> rollMap;

    public BattleOrderCalculator() {
        this.rollMap = new HashMap<>();
    }

    /**
     * 主方法：计算攻击循环序列
     * @param speedMap Map<String, Integer> 人物ID -> 攻速
     * @return 循环的攻击顺序列表
     */
    public List<String> calculateAttackOrder(Map<String, Integer> speedMap) {
        if (speedMap == null || speedMap.isEmpty()) {
            return new ArrayList<>();
        }

        // 步骤1：获取基准攻速（最大值）
        int baseSpeed = Collections.max(speedMap.values());

        // 步骤2：为攻速相同的角色生成 Roll 优先级
        generateRollPriority(speedMap);

        // 步骤3：模拟攻击过程，直到发现循环
        List<String> attackSequence = new ArrayList<>();
        Map<String, Integer> accumulated = new HashMap<>();
        for (String id : speedMap.keySet()) {
            accumulated.put(id, 0);
        }

        // 用于检测循环：记录每个状态首次出现时，攻击序列的长度
        Map<String, Integer> stateToIndex = new HashMap<>();

        while (true) {
            // 当前状态：每个角色的累积值 mod baseSpeed
            String stateKey = getStateKey(accumulated, speedMap.keySet(), baseSpeed);

            // 如果状态已存在，说明从 stateToIndex.get(stateKey) 到现在是循环节
            if (stateToIndex.containsKey(stateKey)) {
                int startIndex = stateToIndex.get(stateKey);
                return new ArrayList<>(attackSequence.subList(startIndex, attackSequence.size()));
            }

            // 记录当前状态对应的攻击序列起始位置
            stateToIndex.put(stateKey, attackSequence.size());

            // 每个角色增加攻速
            for (String id : speedMap.keySet()) {
                accumulated.put(id, accumulated.get(id) + speedMap.get(id));
            }

            // 检查谁可以攻击（累积 >= baseSpeed）
            List<String> canAttack = new ArrayList<>();
            for (String id : speedMap.keySet()) {
                if (accumulated.get(id) >= baseSpeed) {
                    canAttack.add(id);
                }
            }

            // 排序：原始攻速高者优先，相同则按 Roll 值
            canAttack.sort((a, b) -> {
                int speedA = speedMap.get(a);
                int speedB = speedMap.get(b);
                if (speedA != speedB) {
                    return Integer.compare(speedB, speedA); // 高攻速优先
                }
                return Integer.compare(rollMap.get(b), rollMap.get(a)); // Roll 高者优先
            });

            // 执行攻击，记录顺序
            for (String id : canAttack) {
                attackSequence.add(id);
                // 扣除基准攻速
                accumulated.put(id, accumulated.get(id) - baseSpeed);
            }
        }
    }

    /**
     * 生成 Roll 点数，用于决定攻速相同时的角色优先级
     */
    private void generateRollPriority(Map<String, Integer> speedMap) {
        rollMap.clear();
        Random rand = new Random(42); // 固定种子

        Map<Integer, List<String>> groupBySpeed = new HashMap<>();
        for (String id : speedMap.keySet()) {
            groupBySpeed.computeIfAbsent(speedMap.get(id), k -> new ArrayList<>()).add(id);
        }

        for (List<String> group : groupBySpeed.values()) {
            if (group.size() > 1) {
                List<String> shuffled = new ArrayList<>(group);
                Collections.shuffle(shuffled, rand);
                for (int i = 0; i < shuffled.size(); i++) {
                    rollMap.put(shuffled.get(i), i);
                }
            } else {
                rollMap.put(group.get(0), 0);
            }
        }
    }

    /**
     * 生成当前状态的唯一键（基于每个角色的累积值 mod baseSpeed）
     */
    private String getStateKey(Map<String, Integer> accumulated, Set<String> ids, int baseSpeed) {
        List<String> sortedIds = new ArrayList<>(ids);
        sortedIds.sort(String::compareTo);
        StringBuilder sb = new StringBuilder();
        for (String id : sortedIds) {
            sb.append(id).append(":").append(accumulated.get(id) % baseSpeed).append(";");
        }
        return sb.toString();
    }

    // --- 测试 ---
    public static void main(String[] args) {
        BattleOrderCalculator calculator = new BattleOrderCalculator();

        Map<String, Integer> speedMap = new HashMap<>();
        speedMap.put("A", 25);
        speedMap.put("B", 20);
        speedMap.put("C", 20);
        speedMap.put("D", 22);
        speedMap.put("E", 15);

        List<String> order = calculator.calculateAttackOrder(speedMap);
        System.out.println("循环攻击顺序: " + order);
        System.out.println("每轮攻击次数: " + order.size());

        StringBuilder formatted = new StringBuilder();
        for (String s : order) {
            formatted.append(s);
        }
        System.out.println("紧凑表示: " + formatted.toString());
    }
}